require 'rails/generators/migration'
require 'generators/sorcery/helpers'

module Sorcery
  module Generators
    class InstallGenerator < Rails::Generators::Base
      include Rails::Generators::Migration
      include Sorcery::Generators::Helpers

      source_root File.expand_path('templates', __dir__)

      argument :submodules, optional: true, type: :array, banner: 'submodules'

      class_option :model, optional: true, type: :string, banner: 'model',
                           desc: "Specify the model class name if you will use anything other than 'User'"

      class_option :migrations, optional: true, type: :boolean, banner: 'migrations',
                                desc: '[DEPRECATED] Please use --only-submodules option instead'

      class_option :only_submodules, optional: true, type: :boolean, banner: 'only-submodules',
                                     desc: "Specify if you want to add submodules to an existing model\n\t\t\t     # (will generate migrations files, and add submodules to config file)"

      def check_deprecated_options
        return unless options[:migrations]

        warn('[DEPRECATED] `--migrations` option is deprecated, please use `--only-submodules` instead')
      end

      # Copy the initializer file to config/initializers folder.
      def copy_initializer_file
        template 'initializer.rb', sorcery_config_path unless only_submodules?
      end

      def configure_initializer_file
        # Add submodules to the initializer file.
        return unless submodules

        submodule_names = submodules.collect { |submodule| ':' + submodule }

        gsub_file sorcery_config_path, /submodules = \[.*\]/ do |str|
          current_submodule_names = (str =~ /\[(.*)\]/ ? Regexp.last_match(1) : '').delete(' ').split(',')
          "submodules = [#{(current_submodule_names | submodule_names).join(', ')}]"
        end
      end

      def configure_model
        # Generate the model and add 'authenticates_with_sorcery!' unless you passed --only-submodules
        return if only_submodules?

        generate "model #{model_class_name} --skip-migration"
        inject_sorcery_to_model
      end

      def inject_sorcery_to_model
        indents = '  ' * (namespaced? ? 2 : 1)

        inject_into_class(model_path, model_class_name, "#{indents}authenticates_with_sorcery!\n")
      end

      # Copy the migrations files to db/migrate folder
      def copy_migration_files
        # Copy core migration file in all cases except when you pass --only-submodules.
        return unless defined?(ActiveRecord)

        migration_template 'migration/core.rb', 'db/migrate/sorcery_core.rb', migration_class_name: migration_class_name unless only_submodules?

        return unless submodules

        submodules.each do |submodule|
          unless %w[http_basic_auth session_timeout core].include?(submodule)
            migration_template "migration/#{submodule}.rb", "db/migrate/sorcery_#{submodule}.rb", migration_class_name: migration_class_name
          end
        end
      end

      # Define the next_migration_number method (necessary for the migration_template method to work)
      def self.next_migration_number(dirname)
        if ActiveRecord::Base.timestamped_migrations
          sleep 1 # make sure each time we get a different timestamp
          Time.new.utc.strftime('%Y%m%d%H%M%S')
        else
          format('%.3d', (current_migration_number(dirname) + 1))
        end
      end

      private

      def only_submodules?
        options[:migrations] || options[:only_submodules]
      end

      def migration_class_name
        if Rails::VERSION::MAJOR >= 5
          "ActiveRecord::Migration[#{Rails::VERSION::MAJOR}.#{Rails::VERSION::MINOR}]"
        else
          'ActiveRecord::Migration'
        end
      end
    end
  end
end
